﻿using Microsoft.Graphics.Canvas;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Numerics;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.Storage;
using Windows.Storage.Pickers;
using Windows.System;
using Windows.UI;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Animation;
using Windows.UI.Xaml.Media.Imaging;
using Windows.UI.Xaml.Navigation;
using 纸片人.AttributeUsageFloder;
using Color = Windows.UI.Color;
using Point = Windows.Foundation.Point;

// https://go.microsoft.com/fwlink/?LinkId=234238 上介绍了“空白页”项模板

namespace 纸片人.PageViews
{
    [LastModified("2022-5-12", "create LiquefactionPage.xaml")]
    [PageType("cpu", "液化")]
    /// <summary>
    /// 可用于自身或导航至 Frame 内部的空白页。
    /// </summary>
    public sealed partial class LiquefactionPage : Page
    {


        int width;
        int height;
        Color[] colors;
        Color[] tempColors;

        Color[] canceColors;


        CanvasDevice device = new CanvasDevice();

        WriteableBitmap wb;

        int rangeSize = 50;

        double m = 1;

        Point startPoint = new Point();
        double depathX = 0;
        double depathY = 0;

        Point[,] matric;
        Point[,] tempMatric;

        /// <summary>
        /// 鼠标指针位于图片的位置
        /// </summary>
        Point mousePoint = new Point();
        DispatcherTimer timer;

        public LiquefactionPage()
        {
            this.InitializeComponent();

            image.ManipulationMode = ManipulationModes.TranslateX | ManipulationModes.TranslateY;


     

            this.Dispatcher.AcceleratorKeyActivated += Dispatcher_AcceleratorKeyActivated;

            timer = new DispatcherTimer();
            timer.Tick += Timer_Tick;
            timer.Interval = TimeSpan.FromMilliseconds(1);

        }

        double swellStrenth = 1;

        

        private void Timer_Tick(object sender, object e)
        {
    

            if (li3.IsChecked == true || li4.IsChecked == true)
            {
                

                SwellOrExtrusion(startPoint.X, startPoint.Y,swellStrenth);
                swellStrenth++;
            }
            else if(li5.IsChecked == true)
            {
                Distortion(startPoint.X, startPoint.Y, rangeSize / 2, swellStrenth);
                swellStrenth++;
            }

            //Debug.WriteLine(swellStrenth);
        }

        private void Dispatcher_AcceleratorKeyActivated(Windows.UI.Core.CoreDispatcher sender, Windows.UI.Core.AcceleratorKeyEventArgs args)
        {
            if (args.EventType.ToString().Contains("KeyDown"))
            {
                VirtualKey virtualKey = args.VirtualKey;
                if (virtualKey.ToString() == "219")
                {

                    slider.Value = slider.Value - 1 < 1 ? 1 : slider.Value - 1;

                }
                else if (virtualKey.ToString() == "221")
                {
                    slider.Value = slider.Value + 1 > 500 ? 500 : rangeSize + 1;

                 

         

               


                }

                
                
            }

            Debug.WriteLine("有进来" );
        }

       

        /// <summary>
        /// 选择图片
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private async void selectImage_Click(object sender, RoutedEventArgs e)
        {

            CanvasBitmap bitmap = await Function.SelectImageAsync();

            if (bitmap == null)
            {
                return;
            }

            Function.InitialParameter(bitmap, out width, out height, out colors, out tempColors, image, out wb);

            colors.CopyTo(tempColors, 0);
            canceColors = new Color[tempColors.Length];

            matric = new Point[width, height];
            tempMatric = new Point[width, height];
            for (int x = 0; x < width; x++)
            {
                for (int y = 0; y < height; y++)
                {
                    matric[x, y] = new Point(x, y);
                }
            }


        


        }




        /// <summary>
        /// 向前变形液化
        /// </summary>
        /// <param name="cenX">开始点x</param>
        /// <param name="cenY">开始点y</param>
        /// <param name="offsetX">向左偏移</param>
        /// <param name="OffsetY">向右偏移</param>
        /// <param name="r"></param>
        /// <param name="strenth"></param>
        void liquify6(double cenX, double cenY, double offsetX, double offsetY, double r, double strenth)
        {

            double left = cenX - r;
            double right = cenX + r;
            double top = cenY - r;
            double bottom = cenY + r;


            canceColors.CopyTo(tempColors, 0);





            for (int x = (int)left; x < right; x++)
            {



                for (int y = (int)(top); y < bottom; y++)
                {

                    if (x < 0 || x > width - 1 || y < 0 || y > height - 1)
                        continue;
                    double a = x - cenX;
                    double b = y - cenY;

                    double dis = Math.Sqrt(a * a + b * b);

                    if (dis < r)
                    {



                        double ScaleFactor = 1 - (dis / r);
                        ScaleFactor = (strenth / 100d) * ScaleFactor;



                        var ux = x - ((ScaleFactor * offsetX));
                        var uy = y - ((ScaleFactor * offsetY));

                        if (ux < 0 || ux > width - 1 || uy < 0 || uy > height - 1)
                            continue;

                        int ox = (int)Math.Round(ux);
                        int oy = (int)Math.Round(uy);

                        if (smoothSwitch.IsOn)
                        {
                            Color color = Function.BiLinear(ux, uy, canceColors, width, height);
                            tempColors[x + (y * width)] = color;
                        }
                        else
                        {

                            Color c1 = canceColors[ox + (oy * width)];


                            tempColors[(int)x + ((int)y * width)] = c1;
                        }


                    }
                    else
                    {
                        int count = 1;
                    }
                }
            }






        }


        /// <summary>
        /// 向前变形液化
        /// </summary>
        /// <param name="cenX">开始点x</param>
        /// <param name="cenY">开始点y</param>
        /// <param name="offsetX">向左偏移</param>
        /// <param name="OffsetY">向右偏移</param>
        /// <param name="r"></param>
        /// <param name="strenth"></param>
        void liquify(double cenX, double cenY, double offsetX, double offsetY, double r, double strenth)
        {

            double left = cenX - r;
            double right = cenX + r;
            double top = cenY - r;
            double bottom = cenY + r;

            canceColors = new Color[tempColors.Length];
            tempColors.CopyTo(canceColors, 0);

            for (int x = (int)left; x < right; x++)
            {
                for (int y = (int)(top); y < bottom; y++)
                {

                    if (x < 0 || x > width - 1 || y < 0 || y > height - 1)
                        continue;
                    double a = x - cenX;
                    double b = y - cenY;

                    double dis = Math.Sqrt(a * a + b * b);

                    if (dis < r)
                    {



                        double ScaleFactor = 1 - (dis / r);
                        ScaleFactor = strenth / 100d * ScaleFactor;



                        var ux = x - ((ScaleFactor * offsetX));
                        var uy = y - ((ScaleFactor * offsetY));

                        if (ux < 0 || ux > width - 1 || uy < 0 || uy > height - 1)
                            continue;

                        int ox = (int)Math.Round(ux);
                        int oy = (int)Math.Round(uy);

                        //Color color = Function.Smooth(ox, oy, canceColors, width, height);

                        if (smoothSwitch.IsOn)
                        {
                            Color color = Function.BiLinear(ux, uy, canceColors, width, height);
                            tempColors[x + (y * width)] = color;
                        }
                        else
                        {

                            //Color c1 = canceColors[ox + (oy * width)];
                            //tempColors[(int)x + ((int)y * width)] = c1;
                            //Color c1 = canceColors[x + (y * width)];
                            //tempColors[(int)ox + ((int)oy * width)] = c1;
                        }



                    }
                    else
                    {
                        int count = 1;
                    }
                }
            }






        }


      


        /// <summary>
        /// 向前变形液化
        /// </summary>
        /// <param name="cenX">开始点x</param>
        /// <param name="cenY">开始点y</param>
        /// <param name="offsetX">向左偏移</param>
        /// <param name="OffsetY">向右偏移</param>
        /// <param name="r"></param>
        /// <param name="strenth"></param>
        void liquify0(double cenX, double cenY, double offsetX, double offsetY, double r, double strenth)
        {

            double left = cenX - r;
            double right = cenX + r;
            double top = cenY - r;
            double bottom = cenY + r;



            left = Math.Max(left, 0);
            right = Math.Min(right, width - 1);
            top = Math.Max(top, 0);
            bottom = Math.Min(bottom, height - 1);

            MatricCopy();


            for (int x = (int)left; x < right; x++)
            {
                for (int y = (int)(top); y < bottom; y++)
                {

                    if (x < 0 || x > width - 1 || y < 0 || y > height - 1)
                        continue;
                    double a = x - cenX;
                    double b = y - cenY;

                    double dis = Math.Sqrt(a * a + b * b);

                    if (dis < r)
                    {



                        double ScaleFactor = 1 - (dis / r);
                        ScaleFactor = (strenth / 100d) * ScaleFactor;



                        var ux = x - ((ScaleFactor * offsetX));
                        var uy = y - ((ScaleFactor * offsetY));

                        if (ux < 0 || ux > width - 1 || uy < 0 || uy > height - 1)
                            continue;

                        int ox = (int)Math.Round(ux);
                        int oy = (int)Math.Round(uy);

                        Point oriPoint = tempMatric[ox, oy];

                        if (oriPoint.X != ox||oriPoint.Y != oy)
                        {
                            var ddc = 1;
                        }

                        double x1 = oriPoint.X + (ux - ox);
                        double y1 = oriPoint.Y + (uy - oy);

                        if (smoothSwitch.IsOn)
                        {
                            try
                            {



                                Color color = Function.BiLinear(x1, y1, colors, width, height);
                                tempColors[x + (y * width)] = color;
                            }
                            catch
                            {
                                double counttt = x1 + y1;
                            }
                        }
                        else
                        {
                            Color color = colors[(int)oriPoint.X + (int)oriPoint.Y * width];
                            tempColors[x + (y * width)] = color;

                        }

                        //Color color = Function.Smooth(ox, oy, canceColors, width, height);

                        matric[x, y] = new Point(oriPoint.X, oriPoint.Y);

                        //Color color = Function.BiLinear(x1, y1, colors, width, height);




                    }
                    else
                    {
                        int count = 1;
                    }
                }
            }


            //double left = cenX+offsetX - r;
            //double right = cenX + offsetX + r;
            //double top = cenY + offsetY - r;
            //double bottom = cenY + offsetY + r;



            //left = Math.Max(left, 0);
            //right = Math.Min(right, width - 1);
            //top = Math.Max(top, 0);
            //bottom = Math.Min(bottom, height - 1);

            //MatricCopy();

            //double radius = r * r;

            //double transVecModel = offsetX * offsetX + offsetY * offsetY;

            //for (int x = (int)left; x < right; x++)
            //{
            //    for (int y = (int)(top); y < bottom; y++)
            //    {

            //        if (x < 0 || x > width - 1 || y < 0 || y > height - 1)
            //            continue;
            //        double a = x - cenX;
            //        double b = y - cenY;

            //        double dis = (a * a + b * b);

            //        if (dis < radius)
            //        {

            //            double ratio = (radius - dis) / (radius - dis + transVecModel*(100/ strenth));

            //            double ux = x - ratio * ratio *offsetX;
            //            double uy = y - ratio * ratio * offsetY;






            //            if (ux < 0 || ux > width - 1 || uy < 0 || uy > height - 1)
            //                continue;

            //            int ox = (int)Math.Round(ux);
            //            int oy = (int)Math.Round(uy);

            //            Point oriPoint = tempMatric[ox, oy];

            //            double x1 = oriPoint.X + (ux - ox);
            //            double y1 = oriPoint.Y + (uy - oy);

            //            if (smoothSwitch.IsOn)
            //            {
            //                try
            //                {



            //                    Color color = Function.BiLinear(x1, y1, colors, width, height);
            //                    tempColors[x + (y * width)] = color;
            //                }
            //                catch
            //                {
            //                    double counttt = x1 + y1;
            //                }
            //            }
            //            else
            //            {
            //                Color color = colors[(int)oriPoint.X + (int)oriPoint.Y * width];
            //                tempColors[x + (y * width)] = color;

            //            }

            //            //Color color = Function.Smooth(ox, oy, canceColors, width, height);

            //            matric[x, y] = new Point(oriPoint.X, oriPoint.Y);

            //            //Color color = Function.BiLinear(x1, y1, colors, width, height);




            //        }
            //        else
            //        {
            //            int count = 1;
            //        }
            //    }
            //}



        }

        void MatricCopy()
        {
      
            for (int x = 0; x < width; x++)
            {
                for (int y = 0; y < height; y++)
                {
                   Point item = matric[x, y];

                    tempMatric[x, y] = new Point(item.X,item.Y);
                }
            }

        }


        double f = 0;

        /// <summary>
        /// 鼠标拖动
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void image1_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
        {

            f++;
            tbf.Text = f.ToString();
            Point value = e.Position;

            tb.Text = "x:" + value.X + "  y:" + value.Y;


            double sx = value.X / m;
            double sy = value.Y / m;

            double ox = e.Delta.Translation.X / m;
            double oy = e.Delta.Translation.Y / m;

            


            if (li1.IsChecked == true)
            {
                liquify(sx, sy, ox, oy, rangeSize / 2, pressure.Value);
            }
            else if (li2.IsChecked == true)
            {
                depathX += ox;
                depathY += oy;
                ox = depathX;
                oy = depathY;
                sx = startPoint.X;
                sy = startPoint.Y;

              if (ox < 0 && ox < -rangeSize )
                {
                    ox = -rangeSize ;
                }
                else if (ox > 0 && ox > rangeSize )
                {
                    ox = rangeSize ;
                }

                if (oy < 0 && oy < -rangeSize )
                {
                    oy = -rangeSize ;
                }
                else if (oy > 0 && oy > rangeSize )
                {
                    oy = rangeSize ;
                }

                liquify6(sx, sy, ox, oy, rangeSize , pressure.Value);

            }
            else if(li9.IsChecked == true)
            {
                liquify0(sx, sy, ox, oy, rangeSize / 2, pressure.Value);
            }


            Function.InitialImage(tempColors, width, height, image, wb);

        }



        /// <summary>
        /// 鼠标移动，控制圆形
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void image_PointerMoved(object sender, PointerRoutedEventArgs e)
        {
            Point curPoint = e.GetCurrentPoint(image).Position;
            float x = (float)(curPoint.X - ell.Width / 2);
            float y = (float)(curPoint.Y - ell.Height / 2);
            ell.Translation = new Vector3(x, y, 0);

            mousePoint.X = curPoint.X;
            mousePoint.Y = curPoint.Y;

           

            if (li3.IsChecked == true || li4.IsChecked == true || li5.IsChecked == true)
            {
                Point value = e.GetCurrentPoint(image).Position;
                double cx = (int)(value.X / m);
                double cy = (int)(value.Y / m);
                //startPoint.X = cx;
                //startPoint.Y = cy;
                //tempColors.CopyTo(canceColors, 0);
                //swellStrenth = 1;
            }





        }

        /// <summary>
        /// 鼠标离开图片范围
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void image_PointerEntered(object sender, PointerRoutedEventArgs e)
        {
            ell.Visibility = Visibility.Visible;

            ell.Height = ell.Width = rangeSize * m;


        }

        /// <summary>
        /// 鼠标进入图片范围
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void image_PointerExited(object sender, PointerRoutedEventArgs e)
        {
            ell.Visibility = Visibility.Collapsed;
        }



        /// <summary>
        /// 图片更改大小
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void image_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            m = image.ActualWidth / width;
        }

        /// <summary>
        /// 更改圆形大小
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void slider_ValueChanged(object sender, RangeBaseValueChangedEventArgs e)
        {
            rangeSize = (int)slider.Value;

            ell.Height = ell.Width = rangeSize * m;

            float x = (float)(mousePoint.X - ell.Width / 2);
            float y = (float)(mousePoint.Y - ell.Height / 2);
            ell.Translation = new Vector3(x, y, 0);
        }

        /// <summary>
        /// 重置图片
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void reset_Click(object sender, RoutedEventArgs e)
        {
            colors.CopyTo(tempColors, 0);
            Function.InitialImage(colors, width, height, image, wb);


            for (int x = 0; x < width; x++)
            {
                for (int y = 0; y < height; y++)
                {
                    matric[x, y] = new Point(x, y);
                }
            }


        }

        Point cenPoint;

        /// <summary>
        /// 鼠标按下
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void image_PointerPressed(object sender, PointerRoutedEventArgs e)
        {

            Point value = e.GetCurrentPoint(image).Position;
            double cx = (int)(value.X / m);
            double cy = (int)(value.Y / m);
            startPoint.X = cx;
            startPoint.Y = cy;

           if(li2.IsChecked == true)
            {
                tempColors.CopyTo(canceColors, 0);
                 depathX = 0;
                 depathY = 0;
              
                return;
            }
           //else if (li9.IsChecked == true)
           // {
           //     MatricCopy();
           //     depathX = 0;
           //     depathY = 0;
           // }

           //点对点液化
           else if(li6.IsChecked ==true)
            {
                if (cenPoint!=null)
                {
                    //点对点液化
                    var ox = cenPoint.X - value.X;
                    var oy = cenPoint.Y - value.Y;
                    liquify(cenPoint.X, cenPoint.Y, ox, oy, rangeSize / 2, pressure.Value);
                }
                else
                {
                    cenPoint = new Point(value.X,value.Y);
                }
            }

            if (li3.IsChecked == true || li4.IsChecked == true || li5.IsChecked == true)
            {
                tempColors.CopyTo(canceColors, 0);
                timer.Start();
            }


        
        }

       
        /// <summary>
        /// 膨胀或挤压
        /// </summary>
        void SwellOrExtrusion(double cx,double cy,double stre)
        {


            double r = rangeSize / 2;

            double left = cx -r<0?0:cx-r;
            double right = cx +r>width-1?width-1:cx+r;
            double top = cy - r<0?0:cy-r;
            double bottom = cy + r>height-1?height-1:cy+r;

            

            canceColors.CopyTo(tempColors,0);

            double PowRadius = Math.Pow(rangeSize / 2, 2);
          
            for (double y = top; y < bottom; y++)
            {
                double OffSetY = y - cy;
                for (double x = left; x < right; x++)
                {
                    double OffsetX = x - cx;
                    double XY = OffsetX * OffsetX + OffSetY * OffSetY;
                    if (XY <= PowRadius)
                    {

                        double dis = Math.Sqrt(Math.Pow(OffsetX, 2) + Math.Pow(OffSetY, 2));

                        double PosX = 0;
                        double PosY = 0;

                        if (li4.IsChecked == true)
                        {

                            double ScaleFactor = 1d - (XY / PowRadius);
                            ScaleFactor = 1d - (stre / 100) * ScaleFactor;
                            PosX = OffsetX * ScaleFactor + cx;
                            PosY = OffSetY * ScaleFactor + cy;
                        }
                        else
                        {
                            double ScaleFactor = 1d - (XY / PowRadius);
                            ScaleFactor = 1d + (stre / 100) * ScaleFactor;
                            PosX = OffsetX * ScaleFactor + cx;
                            PosY = OffSetY * ScaleFactor + cy;
                        }

                        if (PosX < 0)
                        {
                            PosX = 0;
                        }
                        else if (PosX >= width - 1)
                        {
                            PosX = width - 2;
                        }


                        if (PosY < 0)
                        {
                            PosY = 0;
                        }
                        else if (PosY >= height - 1)
                        {
                            PosY = height - 2;
                        }

                        int Speed = (int)(y * width + x);
                        int index = (int)PosY * width + (int)PosX;


                        Color color = Function.BiLinear(PosX, PosY, canceColors, width, height);
                        //Color c1 = canceColors[((int)PosY * width + (int)PosX)];
                       
                            tempColors[Speed] = color;

                    }

                }
            }


            Function.InitialImage(tempColors, width, height, image, wb);
        }


        /// <summary>
        /// 扭曲
        /// </summary>
        private void Distortion(double cx,double cy,double r, double angle)
        {

            if (colors == null)
                return;
            double va = angle;

            double ang = 0;

            if (rotation.IsOn == true)
            {
                //角度 顺时针
                ang = ((double)(va / 180)) * Math.PI;
            }
            else
            {
                //角度 顺时针
                 ang = ((double)(-va / 180)) * Math.PI;
            }




  

            double left = cx - r < 0 ? 0 : cx - r;
            double right = cx + r > width - 1 ? width - 1 : cx + r;
            double top = cy - r < 0 ? 0 : cy - r;
            double bottom = cy + r > height - 1 ? height - 1 : cy + r;


            double icenterX =cx;
            double icenterY = cy;
            double radius = r;
            double radius2 = radius * radius;


            for (double j = left; j < right; j++)
            {
                for (double i = top; i < bottom; i++)
                {
                    double x = 0, y = 0;

                    double dx = j - icenterX;
                    double dy = i - icenterY;

                    double distance2 = dx * dx + dy * dy;

                    if (distance2 < radius2)
                    {
                        double distance = Math.Sqrt(distance2);
                        double a = Math.Atan2(dy, dx) + ang * (radius - distance) / radius;
                        x = icenterX + distance * Math.Cos(a);
                        y = icenterY + distance * Math.Sin(a);

                        x = x < 0 ? 0 : x;
                        x = x > width - 1 ? width - 2 : x;

                        y = y < 0 ? 0 : y;
                        y = y > height - 1 ? height - 2 : y;

                        //tempColors[(int)(j + i * imageWidth)] = colors[(int)x+ (int)y*imageWidth];
                        tempColors[(int)(j + i * width)] = Function.BiLinear(x, y, canceColors, width, height);

                    }



                }
            }

            Function.InitialImage(tempColors, width, height, image, wb);
        }


        //bool isUp;

        /// <summary>
        /// 鼠标弹起
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void image_PointerReleased(object sender, PointerRoutedEventArgs e)
        {
            timer.Stop();
            //isUp = true;
            //SwellOrExtrusion(startPoint.X, startPoint.Y, swellStrenth);
            //isUp = false;
            swellStrenth = 1;
        }
    }

    public class Test
    {
        public Point OriPoint { get; set; }
    }
   

}
